package cn.learn.office.excel_v3.read;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author huangyezhan
 * @version 2.0
 * @date 2021年06月12日11:12
 */
@Slf4j
public class ReadExcelUtil {
    private ReadExcelUtil() {
    }

    private static final String TYPE = ".xlsx";

    /**
     * 这个默认返回HashMap格式数据
     */
    public static List<T> read(String type, InputStream input, ReadHeader readHeader) {
        return read(type, input, readHeader, null);
    }

    /**
     * 读取Excel数据内容
     *
     * @param type       Excel的格式
     * @param input      输入流
     * @param readHeader 头信息
     * @param clz        使用的对象类型
     * @return 返回读取的结果
     */
    public static List<T> read(String type, InputStream input, ReadHeader readHeader, Class<T> clz) {
        Workbook wb = null;
        try {
            if (TYPE.equals(type)) {
                wb = new XSSFWorkbook(input);
            } else {
                wb = new HSSFWorkbook(input);
            }
            // null和所有的Map下的实现都默认为HashMap
            if (null == clz || Map.class.isAssignableFrom(clz)) {
                return read(wb, readHeader);
            }
            return read(wb, readHeader, clz);
        } catch (IOException e) {
            log.error("IO转Excel错误：{}", e.getMessage());
        } finally {
            try {
                if (null != wb) {
                    wb.close();
                }
            } catch (IOException e) {
                log.error("关闭workbook异常：{}", e.getMessage());
            } finally {
                if (null != input) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        log.error("关闭IO异常：{}", e.getMessage());
                    }
                }
            }
        }
        return null;
    }


    private static List<T> read(Workbook wb, ReadHeader readHeader, Class<T> clz) {
        FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();

        List<T> list = new ArrayList<>();
        try {
            T t = null;
            // 内省机制
            PropertyDescriptor[] pds = Introspector.getBeanInfo(clz, Object.class).getPropertyDescriptors();

            // 读取Excel
            Sheet sheet  = wb.getSheetAt(0);
            int   rowNum = sheet.getLastRowNum();
            Row   row    = null;
            Cell  cell   = null;
            for (int i = 0; i <= rowNum; i++) {
                t = clz.newInstance();
                list.add(t);
                row = sheet.getRow(i);
                List<ReadHeader.HeaderCell> headerCells = readHeader.getList();
                for (ReadHeader.HeaderCell headerCell : headerCells) {
                    cell = row.getCell(headerCell.colIndex());
                    Object o = getCellValue(cell, formulaEvaluator);
                    for (PropertyDescriptor pd : pds) {
                        if (headerCell.name().equals(pd.getName())) {
                            pd.getWriteMethod().invoke(t, o);
                        }
                    }
                }
            }
            return list;
        } catch (IllegalAccessException e) {
            log.error("没有权限访问：{}", e.getMessage());
        } catch (InstantiationException e) {
            log.error("该类是抽象类、接口不允许创建实例：{}", e.getMessage());
        } catch (IntrospectionException e) {
            log.error("内省异常{}", e.getMessage());
        } catch (InvocationTargetException e) {
            log.error("反射异常：{}", e.getMessage());
        }
        return list;
    }

    private static List read(Workbook wb, ReadHeader header) {
        FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();

        List                list = new ArrayList<>();
        Map<String, Object> map  = null;
        //读取Excel
        Sheet sheet  = wb.getSheetAt(0);
        int   rowNum = sheet.getLastRowNum();
        Row   row    = null;
        Cell  cell   = null;
        //读取正真的数据
        for (int i = 0; i <= rowNum; i++) {
            row = sheet.getRow(i);
            map = new HashMap<>(16);
            List<ReadHeader.HeaderCell> headerList = header.getList();
            for (ReadHeader.HeaderCell headerCell : headerList) {
                cell = row.getCell(headerCell.colIndex());
                Object o = getCellValue(cell, formulaEvaluator);
                map.put(headerCell.name(), o);
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 转换单元格格式
     *
     * @param cell             单元格
     * @param formulaEvaluator 公式计算器
     * @return 返回获取出单元格的内容
     */
    private static Object getCellValue(Cell cell, FormulaEvaluator formulaEvaluator) {
        if (cell != null) {
            switch (cell.getCellType()) {
                case NUMERIC:
                    return cell.getNumericCellValue();
                case STRING:
                    return cell.getRichStringCellValue().toString();
                case FORMULA:
                    String s = String.valueOf(formulaEvaluator.evaluate(cell));
                    String[] split = s.split("\"");
                    return split[1];
                case BOOLEAN:
                    return cell.getBooleanCellValue();
                default:
                    return null;
            }
        }
        return null;
    }

}
